use std::{io::Write, time::Duration};

use clap::Parser;
// use clap::{arg, command, value_parser, ArgAction, Command};
use console::{Key, Term};
use telnet::Telnet;

fn rtt_repl(
    mut term: Term,
    mut connection: Telnet,
    terminal_in_send_recv: crossbeam_channel::Receiver<u8>,
) {
    loop {
        if let Ok(c) = terminal_in_send_recv.recv_timeout(Duration::from_millis(1)) {
            let _ = connection.write(&[c]);
        }

        match connection.read_nonblocking() {
            Ok(event) => match event {
                telnet::Event::Data(datain) => {
                    term.write(&datain).unwrap();
                }
                telnet::Event::UnknownIAC(_) => {}
                telnet::Event::Negotiation(_, _) => {}
                telnet::Event::Subnegotiation(_, _) => {}
                telnet::Event::TimedOut => {}
                telnet::Event::NoData => {}
                telnet::Event::Error(e) => {
                    println!("\n{:?}", e);
                    return;
                }
            },

            Err(e) => {
                println!("\n{:?}", e);
                return;
            }
        }
    }
}

fn terminal_read_key(mut term: Term, terminal_in_send: crossbeam_channel::Sender<u8>) {
    loop {
        if let Ok(key) = term.read_key() {
            match key {
                Key::Unknown => {}
                Key::UnknownEscSeq(_) => {}
                Key::ArrowLeft => {}
                Key::ArrowRight => {}
                Key::ArrowUp => {
                    let _ = terminal_in_send.send(0x1b);
                    let _ = terminal_in_send.send(0x5b);
                    let _ = terminal_in_send.send(0x41);
                }
                Key::ArrowDown => {
                    let _ = terminal_in_send.send(0x1b);
                    let _ = terminal_in_send.send(0x5b);
                    let _ = terminal_in_send.send(0x42);
                }
                Key::Enter => {
                    let _ = terminal_in_send.send('\n' as u8);
                    let _ = term.write(&['\n' as u8]);
                }
                Key::Escape => {}
                Key::Backspace => {
                    let _ = terminal_in_send.send('\x08' as u8);
                }
                Key::Home => {}
                Key::End => {}
                Key::Tab => {}
                Key::BackTab => {}
                Key::Alt => {}
                Key::Del => {}
                Key::Shift => {}
                Key::Insert => {}
                Key::PageUp => {}
                Key::PageDown => {}
                Key::Char(c) => {
                    let _ = terminal_in_send.send(c as u8);
                    let _ = term.write(&[c as u8]);
                }
                Key::CtrlC => {}
                _ => {}
            }
        }
    }
}

/// Simple program to greet a person
#[derive(clap::Parser, Debug)]
#[command(version, about = "Openocd RTT Client.", long_about = None)]
struct Args {
    #[arg(default_value_t = String::from("127.0.0.1"))]
    host: String,

    #[arg(short, long, default_value_t = 6000)]
    port: u16,
}

fn main() {
    let args = Args::parse();

    let (terminal_in_send, terminal_in_send_recv) = crossbeam_channel::unbounded::<u8>();

    let term = Term::stdout();
    let term_cloned = term.clone();

    std::thread::spawn(move || terminal_read_key(term, terminal_in_send));

    loop {
        if let Ok(connection) = Telnet::connect((args.host.clone(), args.port), 4096) {
            rtt_repl(
                term_cloned.clone(),
                connection,
                terminal_in_send_recv.clone(),
            );
            println!("{}", console::style("[rttst]: reconnect ...").yellow());
        }

        // while let Ok(_) = terminal_in_send_recv.try_recv() {}

        std::thread::sleep(Duration::from_millis(1));
    }
}
